package cn.zifangsky.queue.questions;

import cn.zifangsky.queue.LinkQueue;
import cn.zifangsky.queue.Queue;
import org.junit.Test;

/**
 * 猫狗队列
 *
 * 实现一种猫狗队列的结构，要求如下：
 * ●　用户可以调用add方法将cat类或dog类的实例放入队列中；
 * ●　用户可以调用pollAll方法，将队列中所有的实例按照进队列的先后顺序依次弹出；
 * ●　用户可以调用pollDog方法，将队列中dog类的实例按照进队列的先后顺序依次弹出；
 * ●　用户可以调用pollCat方法，将队列中cat类的实例按照进队列的先后顺序依次弹出；
 * ●　用户可以调用isEmpty方法，检查队列中是否还有dog或cat的实例；
 * ●　用户可以调用isDogEmpty方法，检查队列中是否有dog类的实例；
 * ●　用户可以调用isCatEmpty方法，检查队列中是否有cat类的实例。
 *
 * @author zifangsky
 * @date 2019/8/30
 * @since 1.0.0
 */
public class Problem_004_CatDogQueue {

    public static class Pet{
        private String type;

        public Pet(String type) {
            this.type = type;
        }

        public String getType() {
            return type;
        }

    }

    public static class Dog extends Pet{

        public Dog() {
            super("dog");
        }

        @Override
        public String toString() {
            return "Dog{" +
                    "type='" + super.type + '\'' +
                    '}';
        }
    }

    public static class Cat extends Pet{

        public Cat() {
            super("cat");
        }

        @Override
        public String toString() {
            return "Cat{" +
                    "type='" + super.type + '\'' +
                    '}';
        }
    }

    /**
     * 对每个Pet添加计数标识
     */
    public static class PetCounter {
        private Pet pet;

        /**
         * 计数标识
         */
        private long count;

        public PetCounter(Pet pet, long count) {
            this.pet = pet;
            this.count = count;
        }

        public Pet getPet() {
            return pet;
        }

        public long getCount() {
            return count;
        }

        public String getPetType(){
            return this.pet.type;
        }
    }

    /**
     * 猫狗队列
     */
    public static class CatDogQueue {
        /**
         * 猫队列
         */
        private Queue<PetCounter> catQueue;
        /**
         * 狗队列
         */
        private Queue<PetCounter> dogQueue;

        /**
         * 计数标识
         */
        private long count;

        public CatDogQueue() {
            this.catQueue = new LinkQueue<>();
            this.dogQueue = new LinkQueue<>();
            this.count = 0;
        }

        public void add(Pet pet) {
            if("cat".equals(pet.type)){
                catQueue.push(new PetCounter(pet, this.count));
            }else if("dog".equals(pet.type)){
                dogQueue.push(new PetCounter(pet, this.count));
            }else{
                throw new IllegalArgumentException("pet type error!");
            }

            count++;
        }

        public Pet pollAll() {
            if(!this.isDogQueueEmpty() && !this.isCatQueueEmpty()){
                if(this.dogQueue.top().count < this.catQueue.top().count){
                    return this.dogQueue.pop().getPet();
                }else{
                    return this.catQueue.pop().getPet();
                }
            }else if(!this.isDogQueueEmpty()){
                return this.dogQueue.pop().getPet();

            }else if(!this.isCatQueueEmpty()){
                return this.catQueue.pop().getPet();
            }else{
                throw new RuntimeException("Both dog and cat queue are empty!");
            }
        }

        public Dog pollDog() {
            if(!this.isDogQueueEmpty()){
                return (Dog) this.dogQueue.pop().getPet();
            }else{
                throw new RuntimeException("Dog queue is empty!");
            }
        }

        public Cat pollCat() {
            if(!this.isCatQueueEmpty()){
                return (Cat) this.catQueue.pop().getPet();
            }else{
                throw new RuntimeException("Cat queue is empty!");
            }
        }

        public boolean isEmpty() {
            return this.isDogQueueEmpty() && this.isCatQueueEmpty();
        }

        public boolean isDogQueueEmpty() {
            return this.dogQueue.isEmpty();
        }

        public boolean isCatQueueEmpty() {
            return this.catQueue.isEmpty();
        }
    }

    /**
     * 测试用例
     */
    @Test
    public void test(){
        Pet dog1 = new Dog();
        Pet cat1 = new Cat();
        Pet dog2 = new Dog();
        Pet cat2 = new Cat();
        Pet dog3 = new Dog();
        Pet cat3 = new Cat();

        CatDogQueue queue = new CatDogQueue();

        queue.add(dog1);
        queue.add(dog2);

        queue.add(cat1);
        queue.add(cat2);
        queue.add(cat3);

        queue.add(dog3);

        if(!queue.isCatQueueEmpty()){
            System.out.println("cat: " + queue.pollCat());
        }

        if(!queue.isDogQueueEmpty()){
            System.out.println("dog: " + queue.pollDog());
        }

        while (!queue.isEmpty()){
            System.out.println(queue.pollAll());
        }
    }

}
